package com.fanx.redis.lock.spring.annotation;

import org.springframework.context.expression.AnnotatedElementKey;
import org.springframework.context.expression.CachedExpressionEvaluator;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.lang.Nullable;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author fanhang
 */
public class RedisLockExpressionEvaluator extends CachedExpressionEvaluator {

	private final Map<CachedExpressionEvaluator.ExpressionKey, Expression> keyCache = new ConcurrentHashMap<>(64);

	/**
	 * Create an {@link EvaluationContext}.
	 * @param target the target object
	 * @param method the method
	 * @param args the method arguments
	 * @return the evaluation context
	 */
	public EvaluationContext createEvaluationContext(Object target, Method method, Object[] args) {
		return new RedisLockEvaluationContext(target, method, args);
	}

	@Nullable
	public Object key(String keyExpression, AnnotatedElementKey methodKey, EvaluationContext evalContext) {
		return getExpression(this.keyCache, methodKey, keyExpression).getValue(evalContext);
	}

	/**
	 *
	 */
	public static class RedisLockEvaluationContext extends MethodBasedEvaluationContext {

		private static final ParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();

		public RedisLockEvaluationContext(Object rootObject, Method method, Object[] arguments) {
			super(rootObject, method, arguments, NAME_DISCOVERER);
		}

	}

}
